package com.supreme.commonmybatis.aspect;

import com.supreme.common.constant.ConsoleColors;
import com.supreme.commonboot.utils.AspectUtils;
import com.supreme.commonmybatis.annotation.SqlFilter;
import com.supreme.commonmybatis.annotation.SqlParam;
import com.supreme.commonmybatis.utils.ParseSqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.function.Consumer;

@Slf4j
@Aspect
@Configuration
public class SqlFilterAspect {

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    /**
     * 切片
     */
    @Pointcut(value = "@within(com.supreme.commonmybatis.annotation.SqlFilter) || @annotation(com.supreme.commonmybatis.annotation.SqlFilter)")
    public void PointCut() {
    }

    @Before("PointCut()")
    public void beforeFilter(JoinPoint joinPoint) throws IllegalAccessException {

    }

    @Around("PointCut()")
    public Object aroundFilter(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        SqlFilter sqlFilter = AspectUtils.findTypeOrMethodAnnotation(proceedingJoinPoint, SqlFilter.class);
        boolean filterTestId = Optional.ofNullable(sqlFilter).map(SqlFilter::filterTest).orElse(false);
//        boolean filterTestId = sqlFilter != null && sqlFilter.filterTest();

        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        final Class<?>[] parameterTypes = method.getParameterTypes();
        for (Class<?> parameterType : parameterTypes) {
            System.out.println(parameterType.getName());
            Optional.ofNullable(AnnotationUtils.findAnnotation(parameterType, SqlParam.class))
                    .map(SqlParam::rangeKey)
                    .ifPresent(rangeKey -> System.out.println("rangeKey: " + rangeKey));
        }

        String sql = ParseSqlUtils.parseSqlSession(proceedingJoinPoint, sqlSessionFactory, boundSql -> {
            if (filterTestId) {
                try {
                    String filterKey = sqlFilter.filterKey();
                    long longValue = sqlFilter.longValue();

                    Object[] joinPointArgs = proceedingJoinPoint.getArgs();
                    FieldUtils.writeDeclaredField(joinPointArgs[0], filterKey, longValue, true);

                    /*String changeSql = boundSql.getSql();
                    if (StringUtils.contains(changeSql, "where")) {
                        changeSql += String.format(" and id = %d", longValue);
                    } else {
                        changeSql += String.format(" where id = %d", longValue);
                    }
                    FieldUtils.writeDeclaredField(boundSql, filterKey, changeSql, true);*/
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });

        ConsoleColors.printf(ConsoleColors.PURPLE_BOLD_BRIGHT, "\n==== SqlFilter Around SQL: ====\n==== [ %s ] ====\n", sql);

        Object proceed = proceedingJoinPoint.proceed();
        return proceed;
    }
}
